iT邦幫忙

2026 iThome 鐵人賽

DAY 12
0
Software Development

玩轉ABCL Lisp!用奇怪偏門的方式學習JavaFX系列 第 12 篇

lesson 3: JavaFX場景和初見JSS Package:怎麼存取JAVA類別資源?

  • 分享至 

  • xImage
  •  

TL;DR

這篇會使用 Java Package 與 JSS Package 改寫 HelloFX,並將 JavaFX Scene 拆分到獨立的 Lisp 檔案。完成後,主程式只負責建立 Application 和顯示 Stage,Scene 的內容則由另一個檔案建立。

使用 Java Package 建立 Application

ABCL與JAVA交互的方式主要是透過JAVA Package和JSS Package,這也是在package.lisp所引入的:

(defpackage :abcl-javafx
  (:use :cl :java :jss))     ;; 將 :jss 先補上

像是我們在一開始申明的HelloFX運行時類別,所使用的#'jnew-runtime-class就是來自JAVA Package。

java:jnew-runtime-class can inject fully synthetic Java classes–and their objects– into the current JVM process whose behavior is specified via closures expressed in Common Lisp.

計畫將Scene的內容,另外規劃成一份檔案。現在將main.lisp調整成以下內容:

(in-package :abcl-javafx)

(defun +MY-APP.start+ (this stage)
  (prog ((java-info-scene (create-java-info-scene)))
     (#"setScene" stage java-info-scene)
     (#"show" stage)))

(defconstant +MY-APP+
  (jnew-runtime-class
   "MyAPP"
   :superclass +application+
   :methods `(("start" :void (,+stage+)
               +MY-APP.start+))
   :access-flags '(:public)))

(jstatic "launch" +application+ +MY-APP+ (jnew-array "java.lang.String" 1))

主類別程序改成申明一個MyAPP的JAVA Runtime Class類別物件,並透過defconstant綁定到常數+MY-APP+。MyAPP同樣繼承javafx.application.Application。

因為ABCL本身可以算是直譯式的,並不一定要定義主類別的main方法,因此直接不定義,改直接在main.lisp透過jstatic執行launch的靜態方法。
jstatic同樣由JAVA Package提供,用來呼叫類別的靜態方法。需要明確指定尋找的類別和衍伸類別,然後是傳入靜態方法的參數。要運行MyAPP可以這麼使用: (jstatic "launch" +application+ +MY-APP+ (jnew-array "java.lang.String" 1))。

Invokes the static method METHOD on class CLASS with ARGS.

使用 JSS 簡化 Java 呼叫

Scene的設定放到另一個檔案中,現在+MY-APP.start+方法只需要建立Scene,並顯示Stage就好。將(jcall "setScene" stage scene)和(jcall "show" stage)透過JSS Package提供的方式改寫:

(jcall "setScene" stage scene)
(jcall "show" stage)

↑
對應
↓

(#"setScene" stage scene)
(#"show" stage)

JSS的全名是「Java Simple Syntax」或「Java Syntax Sucks」。提供一個更簡單的語法使用JAVA Package,像是#"是JSS提供的一個讀取巨集(read-macro),可以簡化#'jcall的用法。其實#'jstatic也可以透過JSS改寫,不過方法必須是以Symbol型別傳入,像是launch可以這樣改寫:

(#"launch" (make-symbol +application+) +MY-APP+ (jnew-array "java.lang.String" 1))

將 Scene 拆分成獨立檔案

將Scene拆分到scenes/java-info.lisp檔案。請先建立scenes目錄,再新增這份檔案:

(in-package :abcl-javafx)

(defun create-java-info-scene ()
  (prog* ((label-java-version (new +label+ (format nil "Hello, Java ~A " (#"getProperty" 'java.lang.System "java.version"))))
          (label-javafx-version (new +label+ (format nil "With JavaFX ~A" (#"getProperty" 'java.lang.System "javafx.version"))))
          (box (new +VBox+ 50.5 (jnew-array-from-list "javafx.scene.Node" `(,label-java-version ,label-javafx-version))))
          (result (new +scene+ box 640 480)))
     (#"setAlignment" box (jfield "javafx.geometry.Pos" "CENTER"))
     (return result)))

把布局(layout)由StackPane改成VBox,JAVA版本資訊和JavaFX版本資訊分別建立Label物件加入VBox。再透過setAlignment設定中央對齊。

更新 ASDF 系統定義

如此一來,就再進一步將Scene的程式拆出來,並透過JSS Package簡化JAVA Package使用方式。更新後的ASDF檔案如下:

(defsystem "abcl-javafx"
  :description "Create GUI Application with ABCL and JavaFX"
  :version "0.0.1"
  :author "lagagain <lagagain@email.com>"
  :licence "MIT"
  :depends-on (#:jss)  
  :serial t
  :components ((:file "package")
               (:file "constants")
               (:file "scenes/java-info")           ;; 將Scene程式碼拆分出來
               (:file "main")))

執行結果

重新載入abcl-javafx系統:

abcl --load run-system.lisp --eval '(quit)'

執行後應該會看到置中的 Java 與 JavaFX 版本資訊,並且分成上下兩行顯示。這表示 Scene 已經由獨立檔案建立,主程式也成功透過 JSS 呼叫 JavaFX 方法。

https://ithelp.ithome.com.tw/upload/images/20260925/20112470gskEVgZFbz.png

下一篇將在這個 Scene 的基礎上加入 CSS,使用外部樣式檔案調整 JavaFX 元件的外觀。


上一篇
lesson 2: Hello ASDF:CLISP的工程文件「Another System Definition Facility」
下一篇
lesson 4: abclFX怎麼使用CSS?從執行指定Hello MyStyle開始
系列文
玩轉ABCL Lisp!用奇怪偏門的方式學習JavaFX 共 13 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言